import {NodeA,ASTree} from './tsAST';
import * as fs from 'fs';
import { exec } from 'child_process';
import{CFG} from './cfg';

export class Class{
    name:string;
    methods:CFG[];
    cons:CFG|null;
    constructor(name:string,methods:CFG[],cons:CFG|null){
        this.name=name;
        this.cons=cons;
        this.methods=methods;
    }
}

export class Program{
    astRoot:NodeA;
    functions:CFG[]=[];
    classes:Class[]=[];
    constructor(root:NodeA){
        this.astRoot=root;
        this.getFuns(this.astRoot);
    }
    getFuns(node:NodeA) {
        if(node.kind=="FunctionDeclaration"){
                let fname="";
                let block:NodeA|null=null;
                for(let funchild of node.children){
                    if(funchild.kind=="Block"){
                        block=funchild;
                        break;
                    }
                    else if(funchild.kind=="Identifier"){
                        fname=funchild.text;
                    }
                }
                if(block==null){
                    console.log("function without block");
                    process.exit();
                }
                let funCFG=new CFG(block.children[1],fname);
                this.functions.push(funCFG);
        }
        if(node.kind=="ClassDeclaration"){
            let cname="";
            let syntaxList:NodeA|null=null;
            for(let child of node.children){
                if(child.kind=="Identifier")
                    cname=child.text;
                if(child.kind=="SyntaxList")
                    syntaxList=child;
            }
            if(syntaxList==null){
                console.log("class without syntaxlist");
                process.exit();
            }
            let cons:CFG|null=null;
            let methods:CFG[]=[];
            for(let child of syntaxList.children){
                if(child.kind=="MethodDeclaration"||child.kind=="Constructor"){
                    let methodName="";
                    let block:NodeA|null=null;
                    for(let mechild of child.children){
                        if(mechild.kind=="Block"){
                            block=mechild;
                            break;
                        }
                        else if(mechild.kind=="Identifier"){
                            methodName=cname+"."+mechild.text;
                        }
                    }
                    if(block==null){
                        console.log("method without block");
                        process.exit();
                    }
                    let methodCFG=new CFG(block.children[1],methodName);
                    if(child.kind=="MethodDeclaration")
                        methods.push(methodCFG);
                    else
                        cons=methodCFG;
                }
                
            }
            // if(cons==null){
            //     console.log("class without constructor");
            //     process.exit();
            // }
            let cl=new Class(cname,methods,cons);
                this.classes.push(cl);
        }
        for(let c of node.children){
            this.getFuns(c)
        }
    }

}
let fileContent = fs.readFileSync('t.ts', 'utf8');//读取t.ts代码内容
let ast:ASTree=new ASTree(fileContent);//用代码内容构造AST
let p=new Program(ast.root);
for(let f of p.functions){
    f.generateDot()
}

for(let c of p.classes){
    for(let m of c.methods){
        m.generateDot()
    }
}